/*
XPTracker - Alternative Agile Tracking Tool
Copyright (C) 2006-2009  Stephen Starkey

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
*/
package org.xptracker.web.tags;

import com.google.inject.Inject;
import org.xptracker.domain.BlogEntry;
import org.xptracker.domain.Domain;
import org.xptracker.domain.Story;
import org.xptracker.domain.UserAccessor;
import org.xptracker.persistence.PersistenceManager;

import javax.servlet.jsp.JspTagException;
import java.io.Serializable;
import java.util.*;

public class BlogEntriesTag extends InjectedLoopTag {
  private BlockEntryGroup entries;
  private UserAccessor user;
  private int days;
  private int limit;
  private int limitPerStory;
  private String var;
  private String storyVar;

  @Inject
  private PersistenceManager mgr;

  @Inject
  private Domain domain;

  public UserAccessor getUser() {
    return user;
  }

  public void setUser(UserAccessor user) {
    this.user = user;
  }

  public int getDays() {
    return days;
  }

  public void setDays(int days) {
    this.days = days;
  }

  public int getLimit() {
    return limit;
  }

  public void setLimit(int limit) {
    this.limit = limit;
  }

  public int getLimitPerStory() {
    return limitPerStory;
  }

  public void setLimitPerStory(int limitPerStory) {
    this.limitPerStory = limitPerStory;
  }

  protected void prepareTemplate() {
    Calendar c = Calendar.getInstance();
    c.add(Calendar.DAY_OF_MONTH, -days);
    List<BlogEntry> entries = domain.listBlogEntriesAfter(c.getTime(), user);
    this.entries = new BlockEntryGroup();

    this.entries.addAll(entries);
  }

  protected boolean hasNext() throws JspTagException {
    return this.entries.iterator().hasNext();
  }

  protected Object next() throws JspTagException {
    List<BlogEntry> entries = this.entries.iterator().next();
    pageContext.setAttribute(this.var, entries);
    if (!entries.isEmpty()) {
      pageContext.setAttribute(this.storyVar, this.entries.storyMap.get(entries.get(0).getStoryId()));
    }
    return entries;
  }

  public void setVar(String var) {
    this.var = var;
  }

  public String getVar() {
    return var;
  }

  public String getStoryVar() {
    return storyVar;
  }

  public void setStoryVar(String storyVar) {
    this.storyVar = storyVar;
  }

  /**
   * NOT thread safe!
   */
  private class BlockEntryGroup implements Serializable {
    private Map<Long, List<BlogEntry>> entries = new LinkedHashMap<Long, List<BlogEntry>>();
    private Iterator<List<BlogEntry>> iterator = null;
    private Map<Long, Story> storyMap = new HashMap<Long, Story>();

    public void addAll(final Collection<BlogEntry> entries) {
      Set<String> allIds = new HashSet<String>();
      for(final BlogEntry entry : entries) {
        allIds.add(String.valueOf(entry.getStoryId()));
      }

      List<Story> allStories = mgr.listObjects(Story.class, allIds);
      for(Story story: allStories) {
        storyMap.put(story.getIdLong(), story);
      }

      for (final BlogEntry entry : entries) {
        List<BlogEntry> entriesForStory = this.entries.get(entry.getStoryId());

        if (entriesForStory == null) {
          entriesForStory = new ArrayList<BlogEntry>();
          if(this.entries.size() < limit) {
            this.entries.put(entry.getStoryId(), entriesForStory);
          }
        }

        if (entriesForStory.size() < limitPerStory) {
          entriesForStory.add(entry);
        }
      }
    }

    public Iterator<List<BlogEntry>> iterator() {
      if (this.iterator == null) {
        this.iterator = this.entries.values().iterator();
      }

      return this.iterator;
    }
  }
}
